﻿using System;
using System.Collections.Generic;
using System.Threading;
using MySql.Data.MySqlClient;

//using QALab.AppCode.WorkManager;
//using System.Configuration;

namespace BingoCommonConfig.Db
{
	/// <summary>
	/// 
	/// </summary>
	public class ConnectionPool
	{
		private string testTable = "players"; // 测试连接是否可用的测试表名，默认没有测试表
		private int initialConnections = 10; // 连接池的初始大小
		private int incrementalConnections = 5;// 连接池自动增加的大小
		private int maxConnections = 50; // 连接池最大的大小
		private List<PooledConnection> m_Pooledconnections = null; // 存放连接池中数据库连接的向量
		private string _mySqlConnection = "";//ConfigurationManager.ConnectionStrings["ConnectSql"].ConnectionString;

		public ConnectionPool(string Connection)
		{
			_mySqlConnection = Connection;
		}

		// 返回连接池的初始大小
		public int getInitialConnections()
		{
			return this.initialConnections;
		}

		//设置连接池的初始大小
		public void setInitialConnections(int initialConnections)
		{
			this.initialConnections = initialConnections;
		}

		//返回连接池自动增加的大小 
		public int getIncrementalConnections()
		{
			return this.incrementalConnections;
		}

		//设置连接池自动增加的大小
		public void setIncrementalConnections(int incrementalConnections)
		{
			this.incrementalConnections = incrementalConnections;
		}

		//返回连接池中最大的可用连接数量
		public int getMaxConnections()
		{
			return this.maxConnections;
		}

		//设置连接池中最大可用的连接数量
		public void setMaxConnections(int maxConnections)
		{
			this.maxConnections = maxConnections;
		}


		//获取测试数据库表的名字
		public String getTestTable()
		{
			return this.testTable;
		}

		//设置测试表的名字
		public void setTestTable(String testTable)
		{
			this.testTable = testTable;
		}

		//创建一个数据库连接池，连接池中的可用连接的数量采用类成员 initialConnections 中设置的值
		public void createPool()
		{
			// 如果己经创建，则返回
			if (m_Pooledconnections != null)
				return;

			m_Pooledconnections = new List<PooledConnection>();
			// 根据 initialConnections 中设置的值，创建连接。
			createConnections(this.initialConnections);
		}

		//创建由 numConnections 指定数目的数据库连接 , 并把这些连接 放入 m_Pooledconnections
		private void createConnections(int numConnections)
		{
			// 循环创建指定数目的数据库连接
			for (int x = 0; x < numConnections; x++)
			{
				if (this.maxConnections > 0 && this.m_Pooledconnections.Count >= this.maxConnections)
					break;

				try
				{
					MySqlConnection tmpConnect = newConnection();
					m_Pooledconnections.Add(new PooledConnection(ref tmpConnect));
				}
				catch (Exception ex)
				{
					//CErrorloger.WriteError(ex.Message);
				}
			}
		}

		//创建一个新的数据库连接并返回它
		private MySqlConnection newConnection()
		{
			// 创建一个数据库连接
			MySqlConnection conn = new MySqlConnection(_mySqlConnection);
			conn.Open();
			return conn;
		}

		//通过调用 getFreeConnection() 函数返回一个可用的数据库连接 , 如果当前没有可用的数据库连接，并且更多的数据库连接不能创
		public MySqlConnection getConnection()
		{
			// 确保连接池己被创建
			if (m_Pooledconnections == null)
				return null; // 连接池还没创建，则返回 null

			MySqlConnection conn = getFreeConnection(); // 获得一个可用的数据库连接
														// 如果目前没有可以使用的连接，即所有的连接都在使用中
			while (conn == null)
			{
				Thread.Sleep(250);
				conn = getFreeConnection(); // 重新再试，直到获得可用的连接，如果
			}
			return conn;
		}

		//本函数从连接池向量 connections 中返回一个可用的的数据库连接，如果 当前没有可用的数据库连接，本函数则根据
		//incrementalConnections 设置 的值创建几个数据库连接，并放入连接池中。 如果创建后，所有的连接仍都在使用中，则返回 null
		private MySqlConnection getFreeConnection()
		{
			// 从连接池中获得一个可用的数据库连接
			MySqlConnection conn = findFreeConnection();
			if (conn == null)
			{
				createConnections(incrementalConnections);
				// 重新从池中查找是否有可用连接
				conn = findFreeConnection();
			}
			return conn;
		}

		//查找连接池中所有的连接，查找一个可用的数据库连接， 如果没有可用的连接，返回 null
		private MySqlConnection findFreeConnection()
		{
			MySqlConnection conn = null;
			PooledConnection pConn = null;
			// 遍历所有的对象，看是否有可用的连接
			for (int i = 0; i < m_Pooledconnections.Count; ++i)
			{
				if (!m_Pooledconnections[i].isBusy())
				{
					conn = m_Pooledconnections[i].getConnection();
					m_Pooledconnections[i].setBusy(true);
					// 测试此连接是否可用
					if (!testConnection(ref conn))
					{
						// 如果此连接不可再用了，则创建一个新的连接，
						// 并替换此不可用的连接对象，如果创建失败，返回 null
						try
						{
							conn = newConnection();
						}
						catch (Exception ex)
						{
							//CErrorloger.WriteError(ex.Message);
							return null;
						}
						m_Pooledconnections[i].setConnection(ref conn);
					}
					break; // 己经找到一个可用的连接，退出
				}
			}
			return conn;// 返回找到到的可用连接
		}

		//测试一个连接是否可用，如果不可用，关掉它并返回 false 否则可用返回 true
		private bool testConnection(ref MySqlConnection conn)
		{
			try
			{
				string sql = $"SELECT count(*) FROM {testTable};";
				MySqlCommand DBComm = new MySqlCommand(sql, conn);
				MySqlDataReader DBReader = DBComm.ExecuteReader();
				DBReader.Close();
			}
			catch
			{
				// 上面抛出异常，此连接己不可用，关闭它，并返回 false;
				closeConnection(conn);
				return false;
			}
			return true;
		}

		//此函数返回一个数据库连接到连接池中，并把此连接置为空闲。 所有使用连接池获得的数据库连接均应在不使用此连接时返回它。
		public void returnConnection(MySqlConnection conn)
		{
			// 确保连接池存在，如果连接没有创建（不存在），直接返回
			if (m_Pooledconnections == null)
				return;

			for (int i = 0; i < m_Pooledconnections.Count; ++i)
			{
				if (conn == m_Pooledconnections[i].getConnection())
				{
					m_Pooledconnections[i].setBusy(false);
					break;
				}
			}
		}

		//刷新连接池中所有的连接对象
		public void refreshConnections()
		{
			// 确保连接池己创新存在
			if (m_Pooledconnections == null)
				return;

			for (int i = 0; i < m_Pooledconnections.Count; ++i)
			{
				if (m_Pooledconnections[i].isBusy())
					Thread.Sleep(5000); //等待5s

				// 关闭此连接，用一个新的连接代替它。
				closeConnection(m_Pooledconnections[i].getConnection());
				MySqlConnection tmpConnect = newConnection();
				m_Pooledconnections[i].setConnection(ref tmpConnect);
				m_Pooledconnections[i].setBusy(false);
			}
		}

		//关闭连接池中所有的连接，并清空连接池。
		public void closeConnectionPool()
		{
			// 确保连接池己创新存在
			if (m_Pooledconnections == null)
				return;

			for (int i = 0; i < m_Pooledconnections.Count; ++i)
			{
				if (m_Pooledconnections[i].isBusy())
					Thread.Sleep(5000); //等待5s

				// 关闭此连接，用一个新的连接代替它。
				closeConnection(m_Pooledconnections[i].getConnection());
				m_Pooledconnections.RemoveAt(i);
			}
			m_Pooledconnections.Clear();
			m_Pooledconnections = null;
		}

		//关闭一个数据库连接
		private void closeConnection(MySqlConnection conn)
		{
			try
			{
				conn.Close();
			}
			catch (Exception ex)
			{
				//CErrorloger.WriteError(ex.Message);
			}
		}
	}
}